using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using System.Web.Security;
using System.IO;
using System.Linq;
using Microsoft.Practices.ServiceLocation;

using MvcCms.Service.Code.Wiki;
using MvcCms.Web.ViewModels;
using WikiPlex;
using WikiPlex.Formatting;
using MvcCms.Data;
using MvcCms.Data.Entities;
using MvcCms.Service.Cache;
using MvcCms.Service;
using MvcCms.Service.Validation;
using MvcCms.Data.Pagination;
using MvcCms.Service.Logging;
using MvcCms.Service.Code;
using MvcCms.Service.Models;

namespace MvcCms.Web.Controllers
{
    public class BackOfficeAjaxController  : MvcCms.Service.Code.BaseClasses.MvcCmsControllerBase
    {
        #region Constructors

        private readonly IAccountService _accountService;
        private readonly ICmsService _cmsService;
        private readonly Portal _currentPortal;
        private readonly IPortalService _portalService;
        private readonly ICacheService _cacheService;
        private readonly IMiscService _miscService;
        private readonly IWikiEngine _wikiEngine;

        public BackOfficeAjaxController(IWikiEngine wikiEngine,IPortalService portalService ,ICmsService cmsService, IAccountService accountService, ICacheService cacheService, IMiscService miscService)
        {
            _cmsService = cmsService;
            _accountService = accountService;
            _cacheService = cacheService;
            _miscService = miscService;
            _portalService = portalService;
            _wikiEngine = wikiEngine;
            _currentPortal = _cacheService.GetCurrentPortal();
        }

        #endregion

        [Authorize(Roles = "Editor")]
        public JsonResult GetSubPageList(int id, string routeval)
        {
            try
            {
                IEnumerable<DTOPage> pages = _cmsService.ListPagesForCategory(id);
                return Json(pages);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult GetCategoryPageList(int id, string routeval)
        {
            try
            {
                IEnumerable<ContentCategory> contentPages = _cmsService.ListCategoriesHierarchy();

                return Json(contentPages);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult GetUnpublishedVersions(int id, string routeval)
        {
            try
            {
                IEnumerable<DTOPage> pages = _cmsService.ListUnpublishedPagesForCategory(id);
                return Json(pages);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult GetFirstCmsPage(int id, string routeval)
        {
            try
            {
                DTOPage pageToEdit = null;
                IEnumerable<ContentCategory> cats = _cmsService.ListCategoriesHierarchy();
                foreach (ContentCategory cat in cats)
                {
                    if (cat.ParentCategory == null)
                    {
                        pageToEdit = _cmsService.GetCurrentPageForCategory(cat.CategoryID);
                        break;
                    }
                }
                return Json(pageToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult GetCmsPage(int id, string routeval)
        {
            try
            {
                DTOPage pageToEdit = _cmsService.GetDTOContentPage(id);
                return Json(pageToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        public JsonResult GetAltLangPage(string data)
        {
            try
            {
                var altlangreq = new JavaScriptSerializer().Deserialize<AltLanguageRequest>(data);
                int langaugeId = altlangreq.LanguageID;
                int parentPageId = altlangreq.ParentPageID;
                DTOPage altpage = _cmsService.GetAltLanguagePage(langaugeId, parentPageId);
                if (altpage == null)
                {
                    return Json(new { exists=false });
                }
                else
                {
                    return Json(altpage);
                }
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }
        [Authorize(Roles = "Editor")]
        public JsonResult GetCatCmsPage(int id, string routeval)
        {
            try
            {
                DTOPage pageToEdit = _cmsService.GetCurrentPageForCategory(id);
                return Json(pageToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult ChangePageOrderDown(int id, string routeval)
        {
            try
            {
                ContentPage pageToEdit = _cmsService.GetContentPage(id);
                if (pageToEdit.IsSubPage)
                {
                    ContentPage pageBelowToEdit = _cmsService.GetContentPage(pageToEdit.ContentPageID, "down");

                    pageBelowToEdit.Importance = pageBelowToEdit.Importance - 1;
                    pageToEdit.Importance = pageToEdit.Importance + 1;

                    _cmsService.EditContentPage(pageBelowToEdit);
                    _cmsService.EditContentPage(pageToEdit);
                }
                else
                {
                    bool issubcat = false;
                    ContentCategory catToEdit = _cmsService.GetContentCategory(pageToEdit.ContentCategory.CategoryID);
                    if (catToEdit.ParentCategory != null)
                    {
                        issubcat = true;
                    }
                    ContentCategory catBelowToEdit =
                        _cmsService.GetContentCategory(pageToEdit.ContentCategory.CategoryID, "down", issubcat);

                    catBelowToEdit.Importance = catBelowToEdit.Importance - 1;
                    catToEdit.Importance = catToEdit.Importance + 1;

                    _cmsService.EditContentCategory(catBelowToEdit);
                    _cmsService.EditContentCategory(catToEdit);
                }

                return Json(new {pageToEdit.ContentCategory.CategoryID});
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex); 
                return Json(new {error = "The page order could not be changed"});
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult ChangePageOrderUp(int id, string routeval)
        {
            string type = "";
            try
            {
                ContentPage pageToEdit = _cmsService.GetContentPage(id);
                if (pageToEdit.IsSubPage)
                {
                    type = "page";
                    ContentPage pageAboveToEdit = _cmsService.GetContentPage(pageToEdit.ContentPageID, "up");

                    pageAboveToEdit.Importance = pageAboveToEdit.Importance + 1;
                    pageToEdit.Importance = pageToEdit.Importance - 1;

                    _cmsService.EditContentPage(pageAboveToEdit);
                    _cmsService.EditContentPage(pageToEdit);
                }
                else
                {
                    type = "category";
                    bool issubcat = false;
                    ContentCategory catToEdit = _cmsService.GetContentCategory(pageToEdit.ContentCategory.CategoryID);
                    if (catToEdit.ParentCategory != null)
                    {
                        issubcat = true;
                    }
                    ContentCategory catAboveToEdit =
                        _cmsService.GetContentCategory(pageToEdit.ContentCategory.CategoryID, "up", issubcat);

                    catAboveToEdit.Importance = catAboveToEdit.Importance + 1;
                    catToEdit.Importance = catToEdit.Importance - 1;

                    _cmsService.EditContentCategory(catAboveToEdit);
                    _cmsService.EditContentCategory(catToEdit);
                }
                return Json(new {pageToEdit.ContentCategory.CategoryID});
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex); 
                return Json(new {error = "The " + type + " order could not be changed"});
            }
        }

        [Authorize(Roles = "Editor")]
        [ValidateInput(false)]
        public JsonResult SavePage(int id, string data, string routeVal)
        {
            try
            {
                int pageId=0;
                var contentpageToEdit = new JavaScriptSerializer().Deserialize<ContentPage>(data);
                ContentPage parentLanguageVersion=null;
                if (contentpageToEdit.ParentLanguageVersion != null)
                {
                    parentLanguageVersion = _cmsService.GetContentPage(contentpageToEdit.ParentLanguageVersion.ContentPageID);
                }
                if (contentpageToEdit.ContentPageID == 0)
                {
                    var newPage = new ContentPage
                      {
                          Body = contentpageToEdit.Body,
                          Title = contentpageToEdit.Title,
                          Description = contentpageToEdit.Description,
                          Summary = contentpageToEdit.Summary,
                          Importance = contentpageToEdit.Importance,
                          AddedDate = DateTime.Now,
                          Approved = true,
                          CommentsEnabled = contentpageToEdit.CommentsEnabled,
                          AnonCommentsEnabled = contentpageToEdit.AnonCommentsEnabled,
                          UseWikiMarkup = contentpageToEdit.UseWikiMarkup,
                          OnlyForMembers = contentpageToEdit.OnlyForMembers,
                          Listed = true,
                          ViewCount = 0,
                          Votes = 0,
                          Language = _miscService.GetLanguage(contentpageToEdit.Language.LanguageID),
                          OnlyForPayingMembers = false,
                          TotalRating = 0,
                          ReleaseDate = DateTime.Now,
                          ExpireDate = DateTime.Parse("12/12/2012"),
                          ParentLanguageVersion = parentLanguageVersion,
                          ShowContributorLink = contentpageToEdit.ShowContributorLink 
                      };

                    var userTmp = _accountService.GetUser();
                    var user = new User
                    {
                        UserID = userTmp.UserID 
                    };

                    var contributor = new User
                    {
                        UserID = new Guid(contentpageToEdit.Contributor.UserID.ToString())
                    };
                    var contentCategory = new ContentCategory
                    {
                        CategoryID = id
                    };

                    newPage.Contributor = contributor;
                    newPage.Editor = user;
                    newPage.ContentCategory = contentCategory;

                    //routeval issubpage
                    newPage.IsSubPage = routeVal == "true";
                    newPage.AddedDate = DateTime.Now;

                    pageId = _cmsService.CreateContentPage(newPage);

                    if (pageId == 0)
                    {
                        //the first title error will be sufficient;
                        var modelState = _cmsService.GetModelStateDictionary();
                        string message = modelState["Title"].Errors[0].ErrorMessage;
                        if (message == "")
                        {
                            message = "An error occured, please contact your web administrator.";
                        }
                        return Json(new {error = message});
                    }
                }
                else
                {
                    ContentPage pageToEdit = _cmsService.GetContentPage(contentpageToEdit.ContentPageID);
                    pageToEdit.Body = contentpageToEdit.Body;
                    //pageToEdit.Title = contentpageToEdit.Title;  passing this along to the service seperate so we can see if a 301 needs to be done
                    pageToEdit.Description = contentpageToEdit.Description;
                    pageToEdit.Summary = contentpageToEdit.Summary;
                    pageToEdit.UpdateDate = DateTime.Now;
                    pageToEdit.Approved = contentpageToEdit.Approved;
                    pageToEdit.CommentsEnabled = contentpageToEdit.CommentsEnabled;
                    pageToEdit.AnonCommentsEnabled = contentpageToEdit.AnonCommentsEnabled;
                    pageToEdit.UseWikiMarkup = contentpageToEdit.UseWikiMarkup;
                    pageToEdit.OnlyForMembers = contentpageToEdit.OnlyForMembers;
                    pageToEdit.ShowContributorLink = contentpageToEdit.ShowContributorLink;
                    User contributor = _accountService.GetUser(new Guid(contentpageToEdit.Contributor.UserID.ToString()));
                    pageToEdit.Contributor = contributor;

                    if (!_cmsService.EditContentPage(pageToEdit, contentpageToEdit.Title))
                    {
                        var modelState = _cmsService.GetModelStateDictionary();
                        string message = modelState["Title"].Errors[0].ErrorMessage;
                        if (message == "")
                        {
                            message = "An error occured, please contact your web administrator.";
                        }
                        return Json(new {error = message});
                    }
                    pageId = pageToEdit.ContentPageID;
                }
                if (contentpageToEdit.ParentLanguageVersion != null)
                {
                    return Json(new { ContentPageID = pageId, contentpageToEdit.IsSubPage, AltLanguageForPageID = contentpageToEdit.ParentLanguageVersion.ContentPageID });
                }
                else
                {
                    return Json(new { ContentPageID = pageId, contentpageToEdit.IsSubPage, AltLanguageForPageID = 0 });
                }

            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex); 
                return Json(new {error = ex.Message});
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult DeletePage(int id)
        {
            try
            {
                ContentPage contentpageToEdit = _cmsService.GetContentPage(id);
                bool issub = contentpageToEdit.IsSubPage;
                bool iscv = contentpageToEdit.IsCategoryPage;
                int catid = contentpageToEdit.ContentCategory.CategoryID;

                _cmsService.DeleteContentPage(contentpageToEdit);
                if (!issub)
                {
                    //list out all static pages and each one with a importance
                    //greater than the page deleted remove one from it
                    IEnumerable<ContentCategory> catpagelist = _cmsService.ListCategoriesHierarchy();
                    foreach (ContentCategory page in catpagelist)
                    {
                        if (page.Importance > contentpageToEdit.Importance)
                        {
                            ContentPage catpage = _cmsService.GetPublishedCategoryContentPage(page.CategoryID);
                            catpage.Importance -= 1;
                            _cmsService.EditContentPage(catpage);
                        }
                    }
                    return Json(new {IsSubPage = false, IsCategoryPage = iscv, CategoryID = catid});
                }
                //list out all pages and each one with a importance
                //greater than the page deleted add one to it
                IEnumerable<DTOPage> subpagelist = _cmsService.ListPagesForCategory(catid);
                foreach (DTOPage page in subpagelist)
                {
                    if (page.Importance > contentpageToEdit.Importance)
                    {
                        ContentPage subpage = _cmsService.GetContentPage(page.ContentPageID);
                        subpage.Importance -= 1;
                        _cmsService.EditContentPage(subpage);
                    }
                }
                return Json(new {IsSubPage = true, CategoryID = catid});
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex); 
                return Json(new {error = ex.Message});
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult DeleteImage(string routeval)
        {
            try
            {
                string foldername = _cacheService.GetCurrentPortal().Name.ToUrlFormat();
                string path = Server.MapPath("~/Uploadedimages/" + foldername);

                string filePath = Path.Combine(path, Path.GetFileName(routeval));
                if (System.IO.File.Exists(filePath) == true)
                {
                    System.IO.File.Delete(filePath);
                    return Json(new { result = "success" });
                }
                else
                {
                    return Json(new { error = "File doesnot exist" });
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                return Json(new { error = "You do not have required permission for this operation " + ex.Message });
            }
            catch (IOException exIO)
            {
                return Json(new { error = "File in use " + exIO.Message });
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Editor")]
        public JsonResult DeleteFile(string routeval)
        {
            try
            {
                string foldername = _cacheService.GetCurrentPortal().Name.ToUrlFormat();
                string path = Server.MapPath("~/Uploadedfiles/" + foldername);

                string filePath = Path.Combine(path, Path.GetFileName(routeval));
                if (System.IO.File.Exists(filePath) == true)
                {
                    System.IO.File.Delete(filePath);
                    return Json(new { result = "success" });
                }
                else
                {
                    return Json(new { error = "File doesnot exist" });
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                return Json(new { error = "You do not have required permission for this operation " + ex.Message });
            }
            catch (IOException exIO)
            {
                return Json(new { error = "File in use " + exIO.Message });
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Admin, Editor")]
        public JsonResult SaveRedirect(Redirect editedRedirect)
        {
            try
            {
                var redirectToEdit = _cmsService.GetRedirect(editedRedirect.OldPage);
                redirectToEdit.NewPage = editedRedirect.NewPage;
                redirectToEdit.Description = editedRedirect.Description;
                redirectToEdit.IsFile = editedRedirect.IsFile;

                if (_cmsService.EditRedirect(redirectToEdit))
                {
                    return Json(new { result = "success" });
                }
                return Json(new { error = "There was a problem saving the redirect." });
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Admin")]
        public JsonResult GetUsers(int page, int rp, string qtype, string query, string sortname, string sortorder)
        {
            //* page - when paging is enabled, represents the page number Flexigrid is requesting.
            //* rp - when paging is enabled, represents the number of results per page.
            //* qtype - the name of the column to search in when performing a keyword search.
            //* query - contains the keyword to use when performing a search
            //* sortname - the column name to sort by.
            //* sortorder - ascending or descending.

            IEnumerable<User> usersData;
            IEnumerable<User> users;
            string sortParam = sortname;
            if (sortorder == "desc") { sortname += " DESC"; }
            int total;
            if (!string.IsNullOrEmpty(qtype) && !string.IsNullOrEmpty(query))
            {
                usersData = _accountService.SearchUsers4Ajax(qtype, query);
                total = usersData.Count();
                users = QueryExtensions.SortBy(usersData.AsQueryable(), sortname)
                                                        .AsPagination(page, rp)
                                                        .ToList();
            }
            else
            {
                usersData = _accountService.ListUsers4Ajax();

                users = QueryExtensions.SortBy(usersData.AsQueryable(), sortname)
                                                        .AsPagination(page, rp)
                                                        .ToList();
                var miscService = ServiceLocator.Current.GetInstance<IMiscService>();
                total = miscService.GetTableRowCount("users", null).RowCount;

            }

            if (users != null)
            {
                var flexigridModel = new FlexigridModel();

                flexigridModel.page = page;
                flexigridModel.total = total;
                foreach (var user in users)
                {
                    var cell = new FlexigridRow()
                    {
                        id = user.UserID.ToString(),
                        cell = GetFlexigridCell(user)
                    };
                    flexigridModel.rows.Add(cell);
                }
                return Json(flexigridModel);
            }
            else
            {
                return Json(new { result = "none" });
            }
        }

        private List<string> GetFlexigridCell(User user)
        {
            List<string> propertyList = new List<string>();

            string editRow = "<a title='Delete' onclick='Delete(\"" + user.UserName + "\")' href='javascript:void(0)'>del</a> | ";
            editRow += "<a title='Edit' href='/Account/EditUser/" + user.UserName + "'>edit</a>";
            propertyList.Add(editRow);
            propertyList.Add(user.UserName);
            propertyList.Add(user.Email);
            propertyList.Add(user.CreationDate.GetValueOrDefault().ToShortDateString() + " " + user.CreationDate.GetValueOrDefault().ToLongTimeString());
            propertyList.Add(user.LastActivityDate.GetValueOrDefault().ToTimeSinceString());
            propertyList.Add(user.IsApproved.ToString());
             
            return propertyList;
        }

        private MacroFormatter GetFormatter()
        {
            var siteRenderers = new IRenderer[] 
            { 
                new TitleLinkRenderer(Url), 
                new TextColorRenderer() ,
                new TextSizeRenderer(),
                new AnyStyleRenderer(),
            };
            IEnumerable<IRenderer> allRenderers = Renderers.All.Union(siteRenderers);
            return new MacroFormatter(allRenderers);
        }

        [ValidateInput(false)]
        [Authorize(Roles = "Editor,Admin")]
        public string TemplatePreview(string source)
        {
            return _wikiEngine.Render(source, GetFormatter());
        }

        [Authorize(Roles = "Editor,Admin")]
        public string GetTemplateSource(string id)
        {
            var templates = _portalService.ListEmailTemplates();
            if (templates.Count() > 0)
            {
                var template = templates
                    .Where(t => t.Name.Equals(id)).FirstOrDefault();
                if (template != null)
                {
                    return template.Body;
                }
                else
                {
                    return "";
                }

            }
            else
            {
                return string.Empty;
            }
        }
    }
}